package compose

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log/slog"
	"os"
	"path/filepath"
	"strings"

	"github.com/compose-spec/compose-go/v2/cli"
	"github.com/donknap/dpanel/common/function"
	"github.com/donknap/dpanel/common/service/storage"
	"github.com/sirupsen/logrus"
)

func WithYamlPath(path string) cli.ProjectOptionsFn {
	return func(options *cli.ProjectOptions) error {
		options.ConfigPaths = append(options.ConfigPaths, path)
		return nil
	}
}

func WithYamlContent(content ...string) cli.ProjectOptionsFn {
	return func(options *cli.ProjectOptions) error {
		if !function.IsEmptyArray(options.ConfigPaths) {
			return errors.New("already configured yaml file path")
		}
		tempPath, _ := storage.Local{}.CreateTempDir("")
		tempEnvFile := filepath.Join(tempPath, ".env")
		for i, c := range content {
			tempComposeFile := filepath.Join(tempPath, fmt.Sprintf("compose.%d.yaml", i))
			err := os.WriteFile(
				tempComposeFile,
				append([]byte("# 此文件由 dpanel 面板生成，请勿修改！ \n# Generated by dpanel, do not modify!\n"), []byte(c)...),
				0666,
			)
			if err != nil {
				slog.Debug("compose create withYamlContent", "err", err)
			}
			options.ConfigPaths = append(options.ConfigPaths, tempComposeFile)
		}

		if !function.IsEmptyMap(options.Environment) {
			err := os.WriteFile(tempEnvFile, []byte(strings.Join(options.Environment.Values(), "\n")), 0666)
			if err != nil {
				slog.Debug("compose create withYamlContent", "err", err)
			}
		}

		options.EnvFiles = append(options.EnvFiles, tempEnvFile)
		return nil
	}
}

func NewCompose(opts ...cli.ProjectOptionsFn) (wrapper *Task, warning, err error) {
	// 自定义解析
	opts = append(opts,
		cli.WithExtension(ExtensionServiceName, ExtService{}),
	)
	options, err := cli.NewProjectOptions(
		[]string{},
		opts...,
	)
	if err != nil {
		return nil, warning, err
	}

	originalFormatter := logrus.StandardLogger().Formatter
	originalOutput := logrus.StandardLogger().Out

	bufOut := new(bytes.Buffer)
	logrus.SetOutput(bufOut)
	logrus.SetFormatter(&logrus.JSONFormatter{
		PrettyPrint:       false,
		DisableTimestamp:  true,
		DisableHTMLEscape: true,
	})
	defer func() {
		logrus.SetOutput(originalOutput)
		logrus.SetFormatter(originalFormatter)
	}()

	project, err := options.LoadProject(context.Background())
	if err != nil {
		return nil, warning, err
	}

	if bufOut.Len() > 0 {
		msg := make([]string, 0)
		var data map[string]string
		reader := bufio.NewReader(bufOut)
		for {
			line, _, err := reader.ReadLine()
			if err != nil {
				break
			}
			if err = json.Unmarshal(line, &data); err == nil && data["level"] != "debug" {
				msg = append(msg, data["msg"])
			}
		}
		warning = errors.New(strings.Join(msg, ", \n"))
	}

	wrapper = &Task{
		Project: project,
	}
	return wrapper, warning, nil
}
